package rpc;

import message.IMessage;
import netty.NettyClient;
import register.IRpcConnectionRegister;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author : zGame
 * @version V1.0
 * @Project: simple-rpc
 * @Package rpc
 * @Description: rpc客户端封装, 目前使用list进行nettyClient的注册, 也可以通过map进行扩展,
 *               具体NettyClient怎么注册,怎么分配,按情况实现即可
 * @date Date : 2022年02月28日 11:02
 */
public class RpcClient implements RpcTaskAction, IRpcConnectionRegister {
    
    private List<NettyClient> rpcConnectionList = new ArrayList<NettyClient>();
    
    private Random random = new Random();
    
    /**
     * <li>
     * <p>调用此方法当前线程会阻塞</>
     * <p>RpcTask是对java TaskFuture进行修改,利用TaskFuture特性实现阻塞和唤醒</p>
     * </li>
     *
     * @param message
     * @param <T>
     * @return
     */
    @Override
    public <T> T get(IMessage message) {
        try {
            String taskId = UUID.randomUUID().toString();
            NettyClient nettyClient = rpcConnectionList.get(random.nextInt(rpcConnectionList.size()));
            CompletableRpcTask rpcTask = new CompletableRpcTask(taskId, nettyClient);
            //RpcTask rpcTask = new RpcTask<>(taskId, nettyClient);
            TaskMessageWrap warp = new TaskMessageWrap(taskId, message);
            return nettyClient.get(warp, rpcTask);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * @param message
     * @param time
     * @param timeUnit
     * @param <T>
     * @return
     */
    @Override
    public <T> T get(IMessage message, long time, TimeUnit timeUnit) {
        try {
            String taskId = UUID.randomUUID().toString();
            NettyClient nettyClient = rpcConnectionList.get(random.nextInt(rpcConnectionList.size()));
            CompletableRpcTask rpcTask = new CompletableRpcTask(taskId, nettyClient);
            TaskMessageWrap warp = new TaskMessageWrap(taskId, message);
            return nettyClient.get(warp, rpcTask, time, timeUnit);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 注册rpc远程通信客户端
     *
     * @param name
     * @param host
     * @param port
     */
    @Override
    public void registerConnection(String name, String host, int port) {
        NettyClient nettyClient = new NettyClient(name, host, port);
        rpcConnectionList.add(nettyClient);
    }
    
    private RpcClient() {
    }
    
    private static class Holder {
        
        static RpcClient client = new RpcClient();
    }
    
    public static RpcClient getInstance() {
        return Holder.client;
    }
}
